﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;




using DotSpatial.Topology;




namespace HAMath
{
    /// <summary>
    ///判断一条线和多边形是否有交集 
    /// </summary>
    public class LineInPolygonRegion
    {


        //Polygon 


        private static List<Coordinate> linePoint;
        private static LineString linearString;



        private static List<Coordinate> polygonPoint;
        private static Polygon polygon;


    
       



        /// <summary>
        /// 判断线是否和多边形有交集 第一个参数为线的顶点的集合   第二个参数为多边形的顶点的集合
        /// 
        /// 参数的选择很纠结，主要是为了通用性  哈哈
        /// </summary>
        /// <param name="linePointCoordinate">构成线的顶点的集合 数组中按照XYZ的顺序存放点的坐标信息</param>
        /// <param name="polygonPointCoordinate">构成多边形的顶点的集合 数组中按照XYZ的顺序存放点的坐标信息</param>
        /// <returns></returns>
      
        
        public static IntersectPolygonResult JudgeLineInPolygon(List<double[]> linePointCoordinate, List<double[]> polygonPointCoordinate)
        //public static bool JudgeLineInPolygon(List<double[]> linePointCoordinate, List<double[]> polygonPointCoordinate)
        {


            IntersectPolygonResult intersectPolygonResult = new IntersectPolygonResult();

            try
            {

                #region 首先是数据有效性的检验

                if (linePointCoordinate == null || polygonPointCoordinate == null)
                {
                    return intersectPolygonResult;
                }


                if (linePointCoordinate.Count < 1 || polygonPointCoordinate.Count < 1)
                {
                    return intersectPolygonResult;
                }

                for (int i = 0; i < linePointCoordinate.Count; i++)
                {
                    if (linePointCoordinate[i].GetLength(0) != 3)
                    {
                        return intersectPolygonResult;
                    }
                }
                for (int i = 0; i < polygonPointCoordinate.Count; i++)
                {
                    if (polygonPointCoordinate[i].GetLength(0) != 3)
                    {
                        return intersectPolygonResult;
                    }
                }

                #endregion


            

                #region 线和多边形的构造

                linePoint = new List<Coordinate>();
                //添加线的点的坐标
                for (int i = 0; i < linePointCoordinate.Count; i++)
                {
                    Coordinate coor = new Coordinate();

                    coor.X = linePointCoordinate[i][0];
                    coor.Y = linePointCoordinate[i][1];
                    coor.Z = linePointCoordinate[i][2];

                    linePoint.Add(coor);
                }

                polygonPoint = new List<Coordinate>();
                //添加多边形的顶点的坐标
                for (int i = 0; i < polygonPointCoordinate.Count; i++)
                {

                    Coordinate coor = new Coordinate();

                    coor.X = polygonPointCoordinate[i][0];
                    coor.Y = polygonPointCoordinate[i][1];
                    coor.Z = polygonPointCoordinate[i][2];

                    polygonPoint.Add(coor);

                }


                linearString = new LineString(linePoint);//定义了一条线 参数为顺序的几个点
                polygon = new Polygon(new LinearRing(polygonPoint));//构建多边形

                #endregion


                intersectPolygonResult.IsInPolygon  = polygon.Intersects(linearString);

                //下面计算线和多边形相交的长度
                if (intersectPolygonResult.IsInPolygon == true)
                {
                    intersectPolygonResult .ResultValue  = GetLineInPolygonLength(linePoint, polygon);
                }
                else
                {
                    intersectPolygonResult.ResultValue = 0.0;
                }



                return intersectPolygonResult;

                //return intersectPolygonResult.IsInPolygon;
              

            }
            catch 
            {
                intersectPolygonResult.IsInPolygon = false;
                intersectPolygonResult.ResultValue = 0.0;
                return intersectPolygonResult;
            }

        }
        /// <summary>
        /// 计算线和多边形的相交的长度
        /// </summary>
        /// <param name="linePoint"></param>
        /// <param name="lineString"></param>
        /// <param name="polygon"></param>
        /// <returns></returns>
        private static double GetLineInPolygonLength(List<Coordinate> linePoint, Polygon polygon)
        {


            //对于2维平面来说，一条线段和多边形相交的情况大概可以分为三种：1 相交0个交点；2 相交1个交点； 3  相交2个交点

            //对于包含多条线段的线来说，情况比较复杂，解决方案：将线分割成多条线段，逐个线段进行分析,最后返回各条线段相交长度之和



            if (linePoint == null || polygon == null)
            {
                return 0.0;
            }

            if (linePoint.Count <= 0)
            {
                return 0.0;
            }


            double area = 0.0;


            for (int i = 0; i < linePoint.Count - 1; i++)
            {

                #region 遍历线的点，用相邻的两个点构建新的线段

                //取线上相邻的两个点重新构建线段
                List<Coordinate> newLine = new List<Coordinate>();
                Point point1 = new Point();//新的线段的起始端点
                Point point2 = new Point();//新的线段的结束断点


                //添加线的点的坐标
                Coordinate coor = new Coordinate();
                coor.X = linePoint[i][0];
                coor.Y = linePoint[i][1];
                coor.Z = linePoint[i][2];

                point1.X = linePoint[i][0];
                point1.Y = linePoint[i][1];
                point1.Z = linePoint[i][2];


                newLine.Add(coor);

                Coordinate coor2 = new Coordinate();
                coor2.X = linePoint[i + 1][0];
                coor2.Y = linePoint[i + 1][1];
                coor2.Z = linePoint[i + 1][2];


                point2.X = linePoint[i + 1][0];
                point2.Y = linePoint[i + 1][1];
                point2.Z = linePoint[i + 1][2];


                newLine.Add(coor2);

                LineString newLinearString = new LineString(newLine);

                #endregion


                #region 判断新的线段和多边形的交集情况，计算长度

                if (polygon.Intersects(newLinearString))//如果线和多边形有公共部分
                {
                    IGeometry ig = polygon.Intersection(newLinearString);//相交的信息


                    if (ig.Coordinates.Count == 1)//如果1个交点 此种情况是恰好有一个点位于多边形的边线上，或者是线段恰好过多边形的一个顶点
                    {
                        #region 线段和多边形有一个交点的情况


                        #endregion
                    }

                    if (ig.Coordinates.Count == 2)//如果有2个交点 包括：1：线段的一个点在内另一个点在外；2：两个点都在内；3：两个点都在外
                    {
                        #region 线段和多边形有2个交点的情况

                        area = area + ig.Coordinates[0].Distance(ig.Coordinates[1]);

                        #endregion

                    }

                }
                else//线和多边形没有公共部分
                {
                }

                #endregion


            }


            return area;

        }


        //public static bool JudgeLineInPolygon(List<Coordinate> linePointcoordinate, Polygon polygon)
        //{


        //    try
        //    {
        //        if (polygon == null)
        //        {
        //            return false;
        //        }
        //        if (linePointcoordinate == null)
        //        {
        //            return false;
        //        }
        //        if (linePointcoordinate.Count < 1)
        //        {
        //            return false;
        //        }



        //        linearString = new LineString(linePointcoordinate);//定义了一条线 参数为顺序的几个点


        //        return polygon.Intersects(linearString );
        //        //return polygon.Intersection(linearString );


        //    }
        //    catch (Exception)
        //    {

        //        return false;
        //    }




        //}


    }
}
